#include "xlcomm/base/logger.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "xlcomm/base/async_log.h"
#include "xlcomm/base/current_thread.h"
#include "xlcomm/base/date_time.h"
#include "xlcomm/base/sync_log.h"

namespace xlcomm {

thread_local char t_errnobuf[512];

// 线程安全的获取错误信息
const char* strerror_tl(int saved_errno) {
  return strerror_r(saved_errno, t_errnobuf, sizeof t_errnobuf);
}

// 默认输出函数（到标准输出）
void DefaultOutputFunc(const char* msg, size_t len) {
  if (msg == nullptr || len <= 0) return;
  if (fwrite(msg, len, 1, stdout) != 1) {
    LOG_SYSERROR(fwrite);
  }
}

// 默认清空缓冲区函数（到标准输出）
void DefaultFlushFunc(void) { fflush(stdout); }

Logger::OutputFunc g_output_func = DefaultOutputFunc;  // 最终输出函数
Logger::FlushFunc g_flush_func = DefaultFlushFunc;     // 清空缓冲区函数
Logger::LogLevel g_log_level = Logger::LogLevel::kInfo;  // 全局日志级别

const char* LogLevelStr[] = {"TRACE ", "DEBUG ", "INFO  ",
                             "WARN  ", "ERROR ", "FATAL "};

Logger::Logger(LogLevel cur_level, const char* source_path, int line,
               const char* func_name)
    : cur_level_(cur_level),
      source_file_(source_path),
      line_(line),
      func_name_(func_name) {
  source_file_.SlashBehind();

  stream_ << DateTime::Format(DateTime::Now()) << ' '
          << CurrentThread::GetThreadId() << ' ' << LogLevelStr[cur_level];
}

Logger::~Logger() {
  Finish();
  const LogStream::Buffer& buffer = stream_.buffer();
  g_output_func(buffer.data(), buffer.used());
  if (cur_level_ == kFatal) {
    g_flush_func();
    abort();
  }
}

void Logger::SetOutputFunc(OutputFunc output_func) {
  g_output_func = output_func;
}

void Logger::SetFlushFunc(FlushFunc flush_func) { g_flush_func = flush_func; }

void Logger::SetLogLevel(LogLevel log_level) { g_log_level = log_level; }

void Logger::SetWriteToFile(const char* file_name, bool sync) {
  if (sync) {
    static SyncLog sync_log(file_name);
    SetOutputFunc(
        [](const char* msg, size_t len) { sync_log.Append(msg, len); });
    SetFlushFunc([]() { sync_log.Flush(); });
  } else {
    static AsyncLog async_log(file_name);
    SetOutputFunc(
        [](const char* msg, size_t len) { async_log.Append(msg, len); });
    SetFlushFunc([]() { async_log.Flush(); });
  }
}

Logger::LogLevel Logger::GetLogLevel() { return g_log_level; }

void Logger::Finish() {
  if (source_file_.length() > 0 && line_ > 0) {
    stream_ << " - " << source_file_.data() << ':' << line_;
    if (strlen(func_name_) > 0) {
      stream_ << ' ' << func_name_ << "()";
    }
    if (cur_level_ == kFatal) {
      stream_ << " abort!!!";
    }
  }
  stream_ << '\n';
}

}  // namespace xlcomm